#include "common.h"

int NET_NonBlock(int fd)
{
    int flags;

    /* Here, there will be two system calls. Todo: Try to use one instead. */
    if ((flags = fcntl(fd, F_GETFL)) == -1) {
        return NET_ERR;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        return NET_ERR;
    }
    
    return NET_OK;
}

int NET_TcpNoDelay(int fd)
{
    int yes = 1;
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
        return NET_ERR;
    }
    
    return NET_OK;
}

int NET_SetSendBuffer(int fd, int buffsize)
{
    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
    {
        return NET_ERR;
    }
    
    return NET_OK;
}

int NET_CreateSocket(int domain) 
{
    int s, on = 1;
    
    if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
        return NET_ERR;
    }
    
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
        return NET_ERR;
    }
    return s;
}


int NET_Listen(int s, struct sockaddr *sa, socklen_t len) 
{
    if (bind(s,sa,len) == -1) {
        close(s);
        return NET_ERR;
    }
    if (listen(s, -1) == -1) {
        close(s);
        return NET_ERR;
    }
    return NET_OK;
}

int NET_TcpServer(int port, char *bindaddr)
{
    int s;
    struct sockaddr_in sa;

    if ((s = NET_CreateSocket(AF_INET)) == NET_ERR) {
        return NET_ERR;
    }

    memset(&sa,0,sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_port = htons(port);
    sa.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
        close(s);
        return NET_ERR;
    }
    if (NET_Listen(s,(struct sockaddr*)&sa,sizeof(sa)) == NET_ERR) {
        return NET_ERR;
    }
    
    return s;
}

int NET_GenericAccept(int s, struct sockaddr *sa, socklen_t *len) 
{
    int fd;

    /* For EPOLLET pattern, should loop accept  */
    while(1) {
        fd = accept(s, sa, len);

        if (fd == -1) {
            if (errno == EINTR) {
                continue;
            } else if (errno == ECONNABORTED) {
                continue;
            } else if (errno = EAGAIN){
                return NET_ERR;
            }
        }
        
        break;
    }
    
    return fd;
}

int NET_TcpAccept(int s) 
{
    int fd;
    struct sockaddr_in sa;
    socklen_t salen = sizeof(sa);

    if ((fd = NET_GenericAccept(s,(struct sockaddr*)&sa,&salen)) == NET_ERR) {
        return NET_ERR;
    }
    
    return fd;
}


